//////////////////////////////////////////////////////////////////////////
#pragma once


//////////////////////////////////////////////////////////////////////////
#include "Math/Math.hpp"


namespace Math
{
	// NOTE: Currently only enough support to allow Matrix44fv to be based
	// on this type.
	class Vector4f
	{
	public:
		// Element index constants.
		static const size_t						kXIndex		=	0;
		static const size_t						kYIndex		=	1;
		static const size_t						kZIndex		=	2;
		static const size_t						kWIndex		=	3;

		// Pull the type from the base Simd definition.
		typedef Vector4f						ValueType_t;
		typedef const Vector4f&					ParamType_t;

		// Construction.
		Vector4f()																					{}
		Vector4f( const Vector4f& rhs ) : mX( rhs.mX ), mY( rhs.mY ), mZ( rhs.mZ ), mW( rhs.mW )	{}
		Vector4f( float x, float y, float z, float w ) : mX( x ), mY( y ), mZ( z ), mW( w )			{}

		// Accessors.
		float						X() const														{return mX;}
		float						Y() const														{return mY;}
		float						Z() const														{return mZ;}
		float						W() const														{return mW;}

		void						X( float x )													{mX = x;}
		void						Y( float y )													{mY = y;}
		void						Z( float z )													{mZ = z;}
		void						W( float w )													{mW = w;}

		// Array access.
		float						operator ()( size_t index ) const								{return (&mX)[ index ];}
		void						operator ()( size_t index, float v )							{(&mX)[ index ] = v;}

		// Operators.
		const Vector4f				operator -() const												{return Vector4f( -mX, -mY, -mZ, -mW );}
		const Vector4f				operator -( const Vector4f& rhs ) const							{return Vector4f( mX - rhs.mX, mY - rhs.mY, mZ - rhs.mZ, mW - rhs.mW );}
		const Vector4f				operator +( const Vector4f& rhs ) const							{return Vector4f( mX + rhs.mX, mY + rhs.mY, mZ + rhs.mZ, mW + rhs.mW );}
		const Vector4f				operator *( float rhs ) const									{return Vector4f( mX * rhs, mY * rhs, mZ * rhs, mW * rhs );}
		const Vector4f				operator /( float rhs ) const									{return Vector4f( mX / rhs, mY / rhs, mZ / rhs, mW / rhs );}

		void						operator -=( const Vector4f& rhs )								{Vector4f result = *this - rhs; *this = result;}
		void						operator +=( const Vector4f& rhs )								{Vector4f result = *this + rhs; *this = result;}
		void						operator *=( float rhs )										{Vector4f result = *this * rhs; *this = result;}
		void						operator /=( float rhs )										{Vector4f result = *this / rhs; *this = result;}

		// Explicit set operation.  Syntactic sugar for X(x); Y(y); Z(z) W(w), also a bit faster.
		void						Set( float x, float y, float z, float w )						{mX = x; mY = y; mZ = z; mW = w;}

		// Assignment.
		const Vector4f&				operator =( const Vector4f& v )									{mX = v.mX; mY = v.mY; mZ = v.mZ; mW = v.mW; return *this;}

		// Static initializers.
		static Vector4f				Zero()															{return Vector4f( 0.0f, 0.0f, 0.0f, 0.0f );}
		static Vector4f				XAxis()															{return Vector4f( 1.0f, 0.0f, 0.0f, 0.0f );}
		static Vector4f				YAxis()															{return Vector4f( 0.0f, 1.0f, 0.0f, 0.0f );}
		static Vector4f				ZAxis()															{return Vector4f( 0.0f, 0.0f, 1.0f, 0.0f );}
		static Vector4f				WAxis()															{return Vector4f( 0.0f, 0.0f, 0.0f, 1.0f );}

	private:
		// Implementation data.
		float						mX;
		float						mY;
		float						mZ;
		float						mW;
	};

	//////////////////////////////////////////////////////////////////////////
	// Not really a vector thing, used for color processing at the moment.
	inline Vector4f					Multiply( const Vector4f& lhs, const Vector4f& rhs )
	{
		return Vector4f(
			lhs.X() * rhs.X(),
			lhs.Y() * rhs.Y(),
			lhs.Z() * rhs.Z(),
			lhs.W() * rhs.W()
			);
	}
}
